package com.onetime.mall.trading.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.onetime.mall.trading.dao.OrderDao;
import com.onetime.mall.trading.entity.IdleItemEntity;
import com.onetime.mall.trading.entity.OrderEntity;
import com.onetime.mall.trading.service.IdleItemService;
import com.onetime.mall.trading.service.OrderService;
import com.onetime.mall.trading.utils.OrderTask;
import com.onetime.mall.trading.utils.OrderTaskHandler;
import com.onetime.mall.trading.utils.PageUtils;
import com.onetime.mall.trading.utils.Query;
import com.onetime.mall.trading.vo.OrdersAndProductsVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;


/**
 * @author Lenovo
 */
@Service("orderService")
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {

    @Autowired
    IdleItemService idleItemService;


    /**
     * 默认分段数量
     */
    private static final Integer segments = 200;

    private static final HashMap<Integer, ReentrantLock> lockMap = new HashMap<>();

    static {
//        if (counts != null) {
//            segments = counts;
//        }
        for (Integer i = 0; i < segments; i++) {
            lockMap.put(i, new ReentrantLock(true));
        }
    }

/*    public void lock(OrderEntity key) {
        ReentrantLock lock = lockMap.get(key.hashCode() % segments);
        lock.lock();
    }


    public void unlock(OrderEntity key) {
        ReentrantLock lock = lockMap.get(key.hashCode() % segments);
        lock.unlock();
    }*/


    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        List<OrderEntity> orderEntityList = baseMapper.selectList(null);
        List<OrdersAndProductsVo> collect = orderEntityList.stream().map(order -> {
            Long idleId = order.getIdleId();
            IdleItemEntity item = idleItemService.getById(idleId);
            OrdersAndProductsVo vo = new OrdersAndProductsVo();
            BeanUtils.copyProperties(order, vo);
            vo.setIdleItem(item);
            return vo;
        }).collect(Collectors.toList());

        PageUtils pageUtils = new PageUtils(this.page(new Query<OrderEntity>().getPage(params), null));
        pageUtils.setList(collect);

        /*IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>()
        );*/

        return pageUtils;
    }

    /*
      新增订单，同时下架闲置
      用了事务串行化，后续要优化，修改更新的sql，增加更新条件，而不是在代码中判断条件
      业务逻辑可优化，改为支付时才下架。
      新功能待做，需要新增订单超时处理
      （订单超时：
      1、重新上架闲置；2、修改订单状态；
      3、确保订单取消前不会影响用户的支付，支付前要判断订单状态并加读锁，取消订单时要判断订单状态为未支付才能取消；
      4、保证延期任务一定执行，即确保任务不会因为系统异常而消失）
     */


    /**
     * 更新订单状态，无验证，后期修改为定制的更新sql
     * 后期改为在支付时下架闲置
     * 让所有异常都会让事务启动(rollbackFor = Exception.class)
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateOrder(OrderEntity orderEntity) {

        /*不可修改的信息，初始化订单*/
       /* orderEntity.setOrderNumber(null);
        orderEntity.setUserId(null);
        orderEntity.setIdleId(null);
        orderEntity.setCreateTime(null);*/

        /*订单刚创建*/
        if (orderEntity.getOrderStatus() == 4) {

            /*todo 取消订单,需要优化，减少数据库查询次数*/

            /*查询订单*/
            OrderEntity order = baseMapper.selectById(orderEntity.getId());

            /*订单未闲置*/
            if (order.getOrderStatus() != 0) {
                return false;
            }
            /*查询订单商品*/
            IdleItemEntity idleItem = idleItemService.getById(order.getIdleId());

            /*商品已下单*/
            if (idleItem.getIdleStatus() == 2) {
//                IdleItemEntity idleItemEntity = new IdleItemEntity();
//                idleItem.setId(order.getIdleId());
//                idleItem.setUserId(idleItemEntity.getUserId());
                idleItem.setIdleStatus(1);

                /*数据库更新订单*/
                if (baseMapper.updateById(orderEntity) == 1) {
                    baseMapper.deleteById(orderEntity.getId());
                    try {
                        /*更新订单商品信息*/
                        idleItemService.updateById(idleItem);
                        return true;
                    } catch (Exception e) {
                        RuntimeException exception = new RuntimeException();
                        e.printStackTrace();
                        throw exception;
                    }
                }
                return false;
            } else {
                try {
                    baseMapper.updateById(orderEntity);
                    return true;
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return baseMapper.updateById(orderEntity) == 1;
    }

//    public static ReentrantLock lock = new ReentrantLock(true);


    /**
     * 添加新的订单
     *
     * @param order 订单
     * @return Boolean
     */
    @Override
    public boolean addOrder(OrderEntity order) {
        /*查询订单商品信息*/
        IdleItemEntity idleItemEntity = idleItemService.getById(order.getIdleId());

        if (idleItemEntity.getIdleStatus() != 1) {
            /*商品状态不可购买*/
            return false;
        }
        IdleItemEntity idleItem = new IdleItemEntity();
        idleItem.setId(order.getIdleId());
        /*// TODO: 2022/4/12  更改商品主人所属（此处有些不妥，应付完款在更改）*/
        /*idleItem.setUserId(order.getUserId());*/
        /*idleItem.setIdleStatus(2);*/

        int key = (int) (order.getIdleId() % 100);
        ReentrantLock lock = lockMap.get(key);
        boolean flag;
        try {
            lock.lock();
            flag = addOrderHelp(idleItem, order);
        } finally {
            lock.unlock();
        }
        return flag;
    }


    /**
     * 获取我的所有订单
     * 同时查询出对应的闲置信息，
     * todo 分页
     * userId建索引
     */
    @Override
    public List<OrdersAndProductsVo> getMyOrder(Long userId) {
        /*查询用户所有订单*/
        QueryWrapper<OrderEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        List<OrderEntity> orderEntityList = baseMapper.selectList(wrapper);

        /*如果有订单*/
        if (orderEntityList != null) {
            /*查出订单对应的信息*/
            List<OrdersAndProductsVo> collect = orderEntityList.stream().map(item -> {
                OrdersAndProductsVo vo = new OrdersAndProductsVo();
                BeanUtils.copyProperties(item, vo);

                Long idleId = item.getIdleId();
                IdleItemEntity byId = idleItemService.getById(idleId);

                vo.setIdleItem(byId);
                return vo;
            }).collect(Collectors.toList());
            return collect;
        }
        return null;
        /*if (list.size() > 0) {
            List<Long> idleIdList = new ArrayList<>();
            for (OrderEntity i : list) {
                idleIdList.add(i.getIdleId());
            }
            List<IdleItemModel> idleItemModelList = idleItemDao.findIdleByList(idleIdList);
            Map<Long, IdleItemModel> map = new HashMap<>();
            for (IdleItemModel idle : idleItemModelList) {
                map.put(idle.getId(), idle);
            }
            for (OrderEntity i : list) {
                i.setIdleItem(map.get(i.getIdleId()));
            }
        }
        return list;*/
    }

    /**
     * 查询用户卖出的闲置
     * iIsolation.READ_COMMITTED:授权读取级别
     * 以操作同一行数据为前提，读事务允许其他读事务和写事务，未提交的写事务禁止其他读事务和写事务。
     * 此隔离级别可以防止更新丢失、脏读，但不能防止不可重复读、幻读。
     * 此隔离级别可以通过“瞬间共享读锁”和“排他写锁”实现。
     */
    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public List<OrdersAndProductsVo> getMySoldIdle(Long userId) {
        /*查询用户的商品信息*/
        QueryWrapper<IdleItemEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId).and(i -> i.ne("idle_status", 0));
        List<IdleItemEntity> list = idleItemService.list(wrapper);
        /*System.out.println("我的商品："+list);*/

        if (list != null) {
            List<OrdersAndProductsVo> collect = list.stream().map(item -> {
                Long id = item.getId();
                OrdersAndProductsVo vo = new OrdersAndProductsVo();
                /*查出包含这些商品的订单*/
                QueryWrapper<OrderEntity> orderEntityQueryWrapper = new QueryWrapper<>();
                orderEntityQueryWrapper.eq("idle_id", id);
                OrderEntity orderEntity = baseMapper.selectOne(orderEntityQueryWrapper);

                if (orderEntity != null) {
                    BeanUtils.copyProperties(orderEntity, vo);
                    IdleItemEntity idleItem = idleItemService.getById(id);
                    vo.setIdleItem(idleItem);
                }
                return vo;
            }).filter(item -> item.getIdleItem() != null).collect(Collectors.toList());

            return collect;
        } else {
            return null;
        }
/*        List<OrderModel> orderList = null;
        if (list.size() > 0) {
            List<Long> idleIdList = new ArrayList<>();
            for (IdleItemModel i : list) {
                idleIdList.add(i.getId());
            }
            orderList = orderDao.findOrderByIdleIdList(idleIdList);
            Map<Long, IdleItemModel> map = new HashMap<>();
            for (IdleItemModel idle : list) {
                map.put(idle.getId(), idle);
            }
            for (OrderModel o : orderList) {
                o.setIdleItem(map.get(o.getIdleId()));
            }
        }
        return orderList;*/
    }

    /**
     * 管理员删除订单
     *
     * @param id 订单id
     * @return true or false
     */
    @Override
    public boolean deleteOrder(Long id) {
        return baseMapper.deleteById(id) == 1;
    }

    /**
     * 得到所有订单（分页）
     *
     * @param params 分页参数
     * @return
     */
    @Override
    public PageUtils getAllOrderByPage(Map<String, Object> params) {
        QueryWrapper<OrderEntity> wrapper = new QueryWrapper<>();
        List<OrderEntity> orderEntityList = baseMapper.selectList(null);
        if (orderEntityList != null) {
            List<OrdersAndProductsVo> collect = orderEntityList.stream().map(item -> {
                OrdersAndProductsVo vo = new OrdersAndProductsVo();
                BeanUtils.copyProperties(item, vo);

                Long idleId = item.getIdleId();
                IdleItemEntity idleItemEntity = idleItemService.getById(idleId);

                vo.setIdleItem(idleItemEntity);
                return vo;
            }).collect(Collectors.toList());
            Query<OrderEntity> query = new Query<>();
            IPage<OrderEntity> iPage = this.page(query.getPage(params), null);
            PageUtils pageUtils = new PageUtils(iPage);
            pageUtils.setList(collect);
            return pageUtils;
        } else {
            return null;
        }
    }


    @Transactional(rollbackFor = Exception.class)
    public boolean addOrderHelp(IdleItemEntity idleItemEntity, OrderEntity orderEntity) {
        /*查询订单商品*/
        IdleItemEntity idleItem = idleItemService.getById(orderEntity.getIdleId());
        if (idleItem.getIdleStatus() != 1) {
            /*商品状态不可购买*/
            return false;
        }
        /*前面商品状态没有更新，所以这个 if 一定成立*/
        if (true) {
            /*OrderEntity one = baseMapper.selectOne(new QueryWrapper<OrderEntity>().eq("idle_id", orderEntity.getIdleId()).eq("user_id",orderEntity.getUserId()));
            if (one != null) {
                return true;
            }*/
            /*插入新的订单*/
            if (baseMapper.insert(orderEntity) == 1) {
                /*订单状态改为待支付状态*/
                orderEntity.setOrderStatus(4);
                /*10分钟未支付则取消订单*/
                OrderTaskHandler.addOrder(new OrderTask(orderEntity, 10 * 60));
                return true;
            } else {
                throw new RuntimeException();
            }
        }
        return false;
    }


}